// Logger.cpp
// 结构化日志系统实现
// 合并了ErrorHandler的功能
// 使用LogConfig统一管理配置

#include "Logger.hh"
#include "LogConfig.hh"
#include <stdarg.h>
#include <string.h>
#include <fstream>
#include <string>
#include <cstring>
#include <ctime>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstdlib>

// 获取单例实例
Logger& Logger::getInstance() {
    static Logger instance;
    return instance;
}

// 构造函数
Logger::Logger() : fLevel(LogLevel::INFO), fOutput(NULL) {
    pthread_mutex_init(&fMutex, NULL);
    // 从LogConfig获取日志文件路径
    LogConfig& config = LogConfig::getInstance();
    std::string logFile = config.getLogFile();
    
    // 初始化时打开日志文件
    fOutput = fopen(logFile.c_str(), "a");
    if (fOutput == NULL) {
        // 如果打开失败，回退到stderr
        fOutput = stderr;
    } else {
        // 设置缓冲区，减少I/O次数
        setvbuf(fOutput, NULL, _IOFBF, 8192);
    }
    
    // 从配置获取日志级别
    int configLevel = config.getGlobalLevel();
    fLevel = (LogLevel)configLevel;
}

// 析构函数
Logger::~Logger() {
    if (fOutput != NULL && fOutput != stderr) {
        fflush(fOutput);
        fclose(fOutput);
        fOutput = NULL;
    }
    pthread_mutex_destroy(&fMutex);
}

// 设置日志级别
void Logger::setLevel(LogLevel level) {
    pthread_mutex_lock(&fMutex);
    fLevel = level;
    pthread_mutex_unlock(&fMutex);
}

// 设置日志输出目标
void Logger::setOutput(FILE* output) {
    pthread_mutex_lock(&fMutex);
    if (output != NULL) {
        fOutput = output;
    }
    pthread_mutex_unlock(&fMutex);
}

// 日志输出函数
void Logger::log(LogLevel level, const char* file, int line, const char* function, const char* format, ...) {
    pthread_mutex_lock(&fMutex);
    
    // 检查日志总开关
    LogConfig& config = LogConfig::getInstance();
    if (!config.isLoggingEnabled()) {
        pthread_mutex_unlock(&fMutex);
        return;
    }
    
    // 检查日志级别
    if (level < fLevel || fLevel == LogLevel::NONE) {
        pthread_mutex_unlock(&fMutex);
        return;
    }
    
    // 输出日志头（根据配置选项）
    if (config.getShowTimestamp()) {
        char timestamp[64];
        getTimestamp(timestamp, sizeof(timestamp));
        fprintf(fOutput, "[%s] ", timestamp);
    }
    
    fprintf(fOutput, "[%s] ", levelToString(level));
    
    if (config.getShowThreadId()) {
        unsigned long threadId = getThreadId();
        fprintf(fOutput, "[TID:%lu] ", threadId);
    }
    
    if (config.getShowFileName() || config.getShowLineNumber() || config.getShowFunctionName()) {
        // 提取文件名（不包含路径）
        const char* filename = strrchr(file, '/');
        if (filename == NULL) {
            filename = strrchr(file, '\\');
        }
        if (filename == NULL) {
            filename = file;
        } else {
            filename++; // 跳过分隔符
        }
        
        fprintf(fOutput, "[");
        bool needComma = false;
        if (config.getShowFileName()) {
            fprintf(fOutput, "%s", filename);
            needComma = true;
        }
        if (config.getShowLineNumber()) {
            if (needComma) fprintf(fOutput, ":");
            fprintf(fOutput, "%d", line);
            needComma = true;
        }
        if (config.getShowFunctionName()) {
            if (needComma) fprintf(fOutput, " ");
            fprintf(fOutput, "%s", function);
        }
        fprintf(fOutput, "] ");
    }
    
    // 输出日志内容
    va_list args;
    va_start(args, format);
    vfprintf(fOutput, format, args);
    va_end(args);
    
    fprintf(fOutput, "\n");
    
    // 每100条日志刷新一次，减少I/O开销（错误日志立即刷新）
    static int logCount = 0;
    if (level >= LogLevel::ERROR || (++logCount % 100 == 0)) {
        fflush(fOutput);
    }
    
    pthread_mutex_unlock(&fMutex);
}

// 获取级别字符串
const char* Logger::levelToString(LogLevel level) const {
    switch (level) {
        case LogLevel::DEBUG: return "DEBUG";
        case LogLevel::INFO: return "INFO";
        case LogLevel::WARNING: return "WARN";
        case LogLevel::ERROR: return "ERROR";
        default: return "UNKNOWN";
    }
}

// 获取时间戳字符串
void Logger::getTimestamp(char* buffer, size_t size) const {
    struct timeval tv;
    struct tm* tm_info;
    
    gettimeofday(&tv, NULL);
    tm_info = localtime(&tv.tv_sec);
    
    snprintf(buffer, size, "%04d-%02d-%02d %02d:%02d:%02d.%03ld",
             tm_info->tm_year + 1900,
             tm_info->tm_mon + 1,
             tm_info->tm_mday,
             tm_info->tm_hour,
             tm_info->tm_min,
             tm_info->tm_sec,
             tv.tv_usec / 1000);
}

// 获取线程ID
unsigned long Logger::getThreadId() const {
    return (unsigned long)pthread_self();
}

// ErrorHandler实现（合并自ErrorHandler.cpp）
#include <fstream>
#include <string>
#include <cstring>
#include <ctime>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstdlib>

// 错误日志文件路径（从LogConfig获取）
static const char* getErrorLogFile() {
    static std::string filePath;
    LogConfig& config = LogConfig::getInstance();
    filePath = config.getErrorLogFile();
    
    // 如果路径包含~，展开它
    if (filePath.find("~/") == 0) {
        const char* home = getenv("HOME");
        if (home && strlen(home) > 0) {
            filePath = std::string(home) + filePath.substr(1);
        } else {
            filePath = "/home" + filePath.substr(1);
        }
    }
    
    return filePath.c_str();
}

// 互斥锁，保护文件写入
static pthread_mutex_t g_error_log_mutex = PTHREAD_MUTEX_INITIALIZER;

// 保存错误信息到文件
static void saveErrorToFile(const char* message) {
    pthread_mutex_lock(&g_error_log_mutex);
    
    const char* filePath = getErrorLogFile();
    
    // 确保目录存在
    char dirPath[512];
    strncpy(dirPath, filePath, sizeof(dirPath) - 1);
    dirPath[sizeof(dirPath) - 1] = '\0';
    
    // 找到最后一个 '/' 并截断
    char* lastSlash = strrchr(dirPath, '/');
    if (lastSlash) {
        *lastSlash = '\0';
        
        struct stat st;
        if (stat(dirPath, &st) != 0) {
            // 目录不存在，创建它
            char cmd[512];
            snprintf(cmd, sizeof(cmd), "mkdir -p %s", dirPath);
            system(cmd);
        }
    }
    
    // 打开文件（追加模式）
    std::ofstream file(filePath, std::ios::app);
    if (file.is_open()) {
        // 获取当前时间
        time_t now = time(NULL);
        struct tm* timeinfo = localtime(&now);
        char timeStr[64];
        strftime(timeStr, sizeof(timeStr), "%Y-%m-%d %H:%M:%S", timeinfo);
        
        // 写入错误信息
        file << "[" << timeStr << "] " << message << std::endl;
        file.close();
    }
    
    pthread_mutex_unlock(&g_error_log_mutex);
}

static const char* codeToString(VideoErrorCode code) {
    switch (code) {
        case VideoErrorCode::SUCCESS: return "SUCCESS";
        case VideoErrorCode::PARAMETER_ERROR: return "PARAMETER_ERROR";
        case VideoErrorCode::BUFFER_OVERFLOW: return "BUFFER_OVERFLOW";
        case VideoErrorCode::FRAME_DROPPED: return "FRAME_DROPPED";
        case VideoErrorCode::RTSP_ERROR: return "RTSP_ERROR";
        default: return "UNKNOWN";
    }
}

static const char* errorNumberToString(ErrorNumber errNum) {
    switch (errNum) {
        case ErrorNumber::ERR_NULL_POINTER: return "ERR_NULL_POINTER";
        case ErrorNumber::ERR_INVALID_FRAME_DATA: return "ERR_INVALID_FRAME_DATA";
        case ErrorNumber::ERR_BUFFER_ACCESS: return "ERR_BUFFER_ACCESS";
        case ErrorNumber::ERR_LIFECYCLE_MANAGEMENT: return "ERR_LIFECYCLE_MANAGEMENT";
        case ErrorNumber::ERR_MEMORY_ACCESS: return "ERR_MEMORY_ACCESS";
        case ErrorNumber::ERR_INVALID_SIZE: return "ERR_INVALID_SIZE";
        case ErrorNumber::ERR_SOURCE_CREATION: return "ERR_SOURCE_CREATION";
        case ErrorNumber::ERR_STREAM_STATE: return "ERR_STREAM_STATE";
        case ErrorNumber::ERR_SCHEDULER_TASK: return "ERR_SCHEDULER_TASK";
        case ErrorNumber::ERR_REFERENCE_COUNT: return "ERR_REFERENCE_COUNT";
        default: return "ERR_UNKNOWN";
    }
}

void ErrorHandler::reportError(VideoErrorCode code, const char* message) {
    char logMsg[512];
    snprintf(logMsg, sizeof(logMsg), "[%s] %s", codeToString(code), message ? message : "");
    LOG_ERROR("%s", logMsg);
    saveErrorToFile(logMsg);
}

void ErrorHandler::logInfo(const char* message) {
    LOG_INFO("%s", message ? message : "");
}

void ErrorHandler::reportErrorWithNumber(VideoErrorCode code, ErrorNumber errNum, const char* message) {
    char logMsg[512];
    snprintf(logMsg, sizeof(logMsg), "[ERR-%d:%s] [%s] %s", 
              static_cast<int>(errNum), errorNumberToString(errNum),
              codeToString(code), message ? message : "");
    LOG_ERROR("%s", logMsg);
    saveErrorToFile(logMsg);
}

void ErrorHandler::logInfoWithNumber(ErrorNumber errNum, const char* message) {
    char logMsg[512];
    snprintf(logMsg, sizeof(logMsg), "[ERR-%d:%s] %s", 
            static_cast<int>(errNum), errorNumberToString(errNum),
            message ? message : "");
    LOG_INFO("%s", logMsg);
    // 只保存真正的错误到文件，不保存INFO级别的日志
    if (errNum == ErrorNumber::ERR_INVALID_FRAME_DATA ||
        errNum == ErrorNumber::ERR_NULL_POINTER ||
        errNum == ErrorNumber::ERR_MEMORY_ACCESS ||
        errNum == ErrorNumber::ERR_INVALID_SIZE ||
        errNum == ErrorNumber::ERR_STREAM_STATE ||
        errNum == ErrorNumber::ERR_SCHEDULER_TASK) {
        saveErrorToFile(logMsg);
    }
}

